home *** CD-ROM | disk | FTP | other *** search
- /*
- MSScript.c
-
- Version 1.0d4
-
- Copyright © Apple Computer UK Ltd. 1992
-
- All rights reserved.
-
- Produced by : UK Developer Technical Support
- AppleLink : UK.DTS
-
- Contains OSA interface of MenuScripter.
-
- Change History :
-
- 9-Jul-92 : NH : File created
- 12-Aug-92 : NH : Added checks for InitEditor
-
- Changes for 1.0d3:
-
- 27-Aug-92 : NH : ExecuteScriptForMenu returns error code
-
- Changes for 1.0d4:
-
- 14-Nov-92 : NH : Gustav now system Extension so don't try to launch it!
- Remove editing from menu item
- */
-
- #include <Memory.h>
- #include <Resources.h>
- #include <TextEdit.h>
- #include <Controls.h>
- #include <Dialogs.h>
- #include <Errors.h>
- #include <Files.h>
- #include <Folders.h>
- #include <Components.h>
- #include <AppleEvents.h>
- #include <OSA.h>
- #include <AppleScript.h>
- #include <AERegistry.h>
- #include <Processes.h>
-
- #include "MSGlobals.h"
- #include "MSUtils.h"
- #include "MSAEUtils.h"
- #include "MSWindow.h"
-
- /*
- Each menu (or menu item) can have a script associated with it. This
- script has an ID equal to 32 * theMenuID + theItem number. A script
- with an item number of 0 applies to the whole menu unless it is
- overridden by a particular script for an item in the menu.
-
- Scripts are stored in two resource types
- 'scpt' is a compiled script as returned by OSAStore()
- 'SCPT' is a raw text script as defined in the resource file
-
- At open application time scripts are built from the 'SCPT' resources
- if there are not any existing complied scripts of that resource ID.
- These are stored in the preferences file for the application.
-
- One problem with the scripted menu commands is that if the application
- name is changed the target is no longer found. This may be addressed later.
-
- In order to execute the scripts the application needs to connect to the
- AppleScript component (called Gustav in the Alpha release). The search
- of the available volumes uses the desktop database. Hence the search is
- limited to hard disks.
-
- */
-
- #define kMaxScriptsInApp 100
- #define kCompiledScriptType kOSAScriptResourceType
- #define kTextScriptType 'SCPT'
-
- struct MyScriptRecord {
- OSAID theScriptID;
- short theResID;
- };
-
- typedef struct MyScriptRecord MyScriptRecord;
-
- ComponentInstance gScriptingComponent;
- short gActiveMenuItem;
- AESendProcPtr oldSendProc;
- long refCon;
- MyScriptRecord *menuScripts;
- short gNumScripts;
- short gPrefsRefFile;
-
- /*
- These are used in documentation but not defined in the interfaces
- */
-
- #ifndef kComponentNotFound
- #define kComponentNotFound -1
- #endif
-
- #define kAEDontRecord 0x00001000
-
- pascal OSErr MySendProc(const AppleEvent* theAppleEvent,
- AppleEvent* reply,
- AESendMode sendMode,
- AESendPriority sendPriority,
- long timeOutInTicks,
- IdleProcPtr idleProc,
- EventFilterProcPtr filterProc,
- long refCon)
- {
- #pragma unused (refCon)
-
- DescType typeCode;
- Size descSize;
- OSErr myErr;
- OSErr ignoreErr;
- OSType whatEvent;
- AppleEvent myCopyAEvt;
-
- myErr = AEDuplicateDesc(theAppleEvent, &myCopyAEvt);
-
- myErr = AEGetAttributePtr(&myCopyAEvt,
- keyEventIDAttr,
- typeType,
- &typeCode,
- (Ptr) &whatEvent,
- sizeof(whatEvent),
- &descSize);
-
- ignoreErr = AEDisposeDesc(&myCopyAEvt);
-
- if (myErr != noErr)
- {
- whatEvent = '????';
- }
-
- /*
- Record the final Set Data that occurs due to a script
- 'gdte' = id sent to get 'aete' resource from app, dealt with
- by system handler.
- */
- if ((sendMode & kAEDontRecord) &&
- ((whatEvent!=kAEGetData) && (whatEvent!='gdte')))
- sendMode = sendMode - kAEDontRecord;
-
- /* will be this when a5 bug fixed
- return((*oldSendProc)(theAppleEvent,
- reply,
- sendMode,
- sendPriority,
- timeOutInTicks,
- idleProc,
- filterProc,
- refCon));
- */
-
- return(AESend(theAppleEvent,
- reply,
- sendMode,
- sendPriority,
- timeOutInTicks,
- idleProc,
- filterProc));
- } /* MySendProc */
-
- pascal OSAID GetScriptIDForResID(short lookForID)
- {
- short ctr;
-
- for (ctr=0; ctr<gNumScripts; ctr++)
- {
- if (menuScripts[ctr].theResID==lookForID)
- return(menuScripts[ctr].theScriptID);
- }
-
- return(kOSANullScript);
- }
-
- /*
- Name : GetOpenPreferencesResourceFile
- Purpose : Opens the prefs file, in the system prefs folder
- creating it if it is not found. Sets the current
- resource file to the prefs file so that resources
- will be read from there in preference to the app
- if they have been overridden, and new resources
- will be created in it.
- */
-
- pascal OSErr GetOpenPreferencesResourceFile(short *theRefNum)
- {
- short foundVRefNum;
- long foundDirID;
- OSErr myErr;
-
- myErr = FindFolder(kOnSystemDisk,
- kPreferencesFolderType,
- kCreateFolder,
- &foundVRefNum,
- &foundDirID);
-
- if (myErr==noErr)
- {
-
- *theRefNum = HOpenResFile(foundVRefNum, foundDirID, "\pMenuScripter Prefs", fsWrPerm);
- myErr = ResError();
-
- if (myErr==fnfErr)
- {
- HCreateResFile(foundVRefNum, foundDirID, "\pMenuScripter Prefs");
- myErr = ResError();
-
- *theRefNum = HOpenResFile(foundVRefNum, foundDirID, "\pMenuScripter Prefs", fsWrPerm);
- myErr = ResError();
- }
- }
- return(myErr);
- }
-
- pascal OSErr ClosePrefsResFile(short theRefNum)
- {
- CloseResFile(theRefNum);
- return(ResError());
- }
-
- /*
- Name : AddMenuScript
- Purpose : Adds a compiled script OSAID into the
- global menuScripts array for later access
- */
- pascal void AddMenuScript(short thisID, OSAID thisScriptID)
- {
- if (gNumScripts<kMaxScriptsInApp)
- {
- menuScripts[gNumScripts].theResID = thisID;
- menuScripts[gNumScripts].theScriptID = thisScriptID;
- gNumScripts ++;
- }
- }
-
- /*
- Name : BuildMenuScripts
- Purpose : Reads compiled scripts from the prefs file,
- Any uncompiled scripts ('SCPT' resources with
- no 'Scpt' of same id are compiled, and a compiled
- version stored in the prefs file. Any which fail
- to compile are ignored.
- */
- pascal void BuildMenuScripts(void)
- {
- short numScripts;
- short index;
- short thisID;
- ResType thisType;
- Handle myScript;
- AEDesc myLoadScriptDesc;
- AEDesc myStoreScriptDesc;
- OSAID myLoadID;
- OSErr myErr;
- OSErr ignoreErr;
- Str255 resName;
-
- GetOpenPreferencesResourceFile(&gPrefsRefFile);
-
- gNumScripts = 0;
-
- menuScripts = (MyScriptRecord *)NewPtr(sizeof(MyScriptRecord)*kMaxScriptsInApp);
-
- numScripts = Count1Resources(kCompiledScriptType);
- for (index=0; index <numScripts; index++)
- {
- myScript = Get1IndResource(kCompiledScriptType, index+1);
- GetResInfo(myScript, &thisID, &thisType, resName);
-
- HLock(myScript);
-
- myErr = AECreateDesc(typeOSAGenericStorage,
- (Ptr)*myScript,
- GetHandleSize(myScript),
- &myLoadScriptDesc);
-
- HUnlock(myScript);
-
- if (myErr==noErr)
- {
- myLoadID = 0; // Added for Gustav a8
-
- myErr = OSALoad(gScriptingComponent,
- &myLoadScriptDesc,
- 0,
- &myLoadID);
-
- if (myErr==noErr)
- AddMenuScript(thisID,myLoadID);
- }
-
- ignoreErr = AEDisposeDesc(&myLoadScriptDesc);
- }
-
- numScripts = CountResources(kTextScriptType);
- for (index=0; index <numScripts; index++)
- {
- myScript = GetIndResource(kTextScriptType, index+1);
- GetResInfo(myScript, &thisID, &thisType, resName);
-
- if (GetScriptIDForResID(thisID)==kOSANullScript)
- {
- HLock(myScript);
-
- myErr = AECreateDesc(typeChar,
- (Ptr)*myScript,
- GetHandleSize(myScript),
- &myLoadScriptDesc);
-
- HUnlock(myScript);
-
- if (myErr==noErr)
- {
- myLoadID = 0; // Added for alpha 8
-
- myErr = OSACompile(gScriptingComponent,
- &myLoadScriptDesc,
- 0,
- &myLoadID);
-
- if (myErr==noErr)
- AddMenuScript(thisID,myLoadID);
-
- if (myErr==noErr)
- {
- myErr = OSAStore(gScriptingComponent,
- myLoadID,
- typeOSAGenericStorage,
- 0,
- &myStoreScriptDesc);
-
- if (myErr==noErr)
- {
- myScript = myStoreScriptDesc.dataHandle;
-
- HandToHand(&myScript);
- AddResource(myScript, kCompiledScriptType, thisID, "\pMenu Script");
- }
-
- myErr = AEDisposeDesc(&myStoreScriptDesc);
- }
-
- }
-
- ignoreErr = AEDisposeDesc(&myLoadScriptDesc);
- }
- }
- }
-
- /*
- Name: InitEditorScripting
- Purpose:Connects to the AppleScript component.
- If not currently running it searches all volumes
- with a desktop database, and launches it if found.
- It then tries for approx. 1 min to connect to the
- newly launched AppleScript component.
- */
- pascal OSErr InitEditorScripting(void)
- {
- OSErr myErr;
- ComponentDescription descr;
- ComponentDescription capabilities;
- Component myComponent;
- EventRecord myEvent;
- short retryCount;
-
- SetCursor(&waitCursor);
-
- // Out of date stuff - now it's an extension!
- // myErr = EnsureGustavIsLaunched();
- // if (myErr)
- // return(myErr);
-
- retryCount = 0;
-
- do {
-
- /* Don't lose the high level events - expect a null back */
-
- myErr = WaitNextEvent(mDownMask+mUpMask+keyDownMask+keyUpMask+autoKeyMask,
- &myEvent,
- 240, /* 4 seconds */
- nil);
-
- descr.componentType = kOSAComponentType;
- descr.componentSubType = kAppleScriptSubtype;
- descr.componentManufacturer = (OSType) 0;
- descr.componentFlags = kOSASupportsCompiling +
- kOSASupportsGetSource +
- kOSASupportsAESending;
-
- descr.componentFlagsMask = descr.componentFlags;
-
- myComponent = FindNextComponent(nil, &descr);
-
- retryCount++;
-
- } while (myComponent==nil && retryCount<15); /* Try for one minute */
-
- if (myComponent==nil)
- return(kComponentNotFound);
- else
- {
- myErr = GetComponentInfo(myComponent,
- &capabilities,
- nil,
- nil,
- nil);
-
- gScriptingComponent = OpenComponent(myComponent);
-
- if (gScriptingComponent==nil)
- return(kComponentNotFound);
- }
-
- myErr = OSAGetSendProc(gScriptingComponent,
- &oldSendProc,
- &refCon);
-
- myErr = OSASetSendProc(gScriptingComponent,
- MySendProc,
- 0);
-
- menuScripts = nil;
-
- BuildMenuScripts();
-
- SetCursor(&qd.arrow);
-
- return(myErr);
- }
-
- /*
- Name : CloseEditorScripting
- Purpose : Shutdown of editor scripting capabilities
- */
- pascal OSErr CloseEditorScripting(void)
- {
- OSErr myErr;
- short ctr;
-
- ClosePrefsResFile(gPrefsRefFile);
-
- for (ctr=0; ctr<gNumScripts; ctr++)
- myErr = OSADispose(gScriptingComponent, menuScripts[ctr].theScriptID);
-
- myErr = CloseComponent(gScriptingComponent);
-
- return(myErr);
- }
-
- /*
- Name: DisplayErrorInScript
- Purpose: Put up an alert showing the error text for the last error.
- Also selects the responsible text in theHTE if one is supplied
- */
-
- pascal void DisplayErrorInScript(TEHandle theHTE)
- {
- Str255 errorMessageText;
- AEDesc errRangeDesc;
- AEDesc errRecordDesc;
- AEDesc errTextDesc;
- AEDesc errNumberDesc;
- DescType typeCode;
- Size actSize;
- OSErr myErr;
- OSErr ignoreErr;
- OSErr errorNumber;
- short errorStart;
- short errorEnd;
-
- SetCursor(&qd.arrow);
-
- myErr = OSAScriptError(gScriptingComponent,
- kOSAErrorNumber,
- typeShortInteger,
- &errNumberDesc);
-
- myErr = GetIntegerFromDescriptor(&errNumberDesc, &errorNumber);
-
- ignoreErr = AEDisposeDesc(&errNumberDesc);
-
- myErr = OSAScriptError(gScriptingComponent,
- kOSAErrorMessage,
- typeChar,
- &errTextDesc);
-
- myErr = GetPStringFromDescriptor(&errTextDesc, errorMessageText);
-
- ignoreErr = AEDisposeDesc(&errTextDesc);
-
- if (theHTE)
- {
- myErr = OSAScriptError(gScriptingComponent,
- kOSAErrorRange,
- typeOSAErrorRange,
- &errRangeDesc);
-
- myErr = AECoerceDesc(&errRangeDesc, typeAERecord, &errRecordDesc);
-
- ignoreErr = AEDisposeDesc(&errRangeDesc);
-
- myErr = AEGetKeyPtr(&errRecordDesc,
- keyOSASourceStart,
- typeShortInteger,
- &typeCode,
- (Ptr)&errorStart,
- sizeof(errorStart),
- &actSize);
-
- myErr = AEGetKeyPtr(&errRecordDesc,
- keyOSASourceEnd,
- typeShortInteger,
- &typeCode,
- (Ptr)&errorEnd,
- sizeof(errorEnd),
- &actSize);
-
- ignoreErr = AEDisposeDesc(&errRecordDesc);
-
- TESetSelect(errorStart, errorEnd, theHTE);
- }
-
- ShowError(errorMessageText, errorNumber);
- }
- /*
- Name : CompileDocument
- Purpose : Compiles the text of the supplied document - does NOT keep
- a compiled version - merely checks that it will compile for now
- */
- pascal OSErr CompileDocument(DPtr theDoc)
- {
- OSErr myErr;
- OSErr ignoreErr;
- TEHandle theHTE;
- AEDesc windowTextDesc;
- AEDesc myCompiledText;
- AEDesc styledTextDesc;
- AEDesc textStyleDesc;
- AEDesc rawTextDesc;
- OSAID myScriptID;
-
- /*
- Initialise handles
- */
-
- myCompiledText.dataHandle = nil;
- windowTextDesc.dataHandle = nil;
-
- theHTE = theDoc->theText;
-
- HLock((Handle)(**theHTE).hText);
- myErr = AECreateDesc(typeChar,
- (Ptr)&(*(**theHTE).hText)[0],
- (**theHTE).teLength,
- &windowTextDesc);
-
- HUnlock((Handle)(**theHTE).hText);
-
- if (myErr==noErr)
- {
- myScriptID = 0; // Added for Gustav 1.0a8
-
- myErr = OSACompile(gScriptingComponent,
- &windowTextDesc,
- 0,
- &myScriptID);
-
- if (myErr==noErr)
- {
- myErr = OSAGetSource(gScriptingComponent,
- myScriptID,
- typeStyledText,
- &myCompiledText);
- if (myErr==noErr)
- {
- styledTextDesc.dataHandle = nil;
- textStyleDesc.dataHandle = nil;
- rawTextDesc.dataHandle = nil;
-
- /*
- Coerce to an AERecord and then extract the parts of the
- styled text
- */
- myErr = AECoerceDesc(&myCompiledText, typeAERecord, &styledTextDesc);
-
- myErr = AEGetKeyDesc(&styledTextDesc,
- keyAEText,
- typeChar,
- &rawTextDesc);
-
- myErr = AEGetKeyDesc(&styledTextDesc,
- keyAEStyles,
- typeScrapStyles,
- &textStyleDesc);
-
- TESetSelect(0,32000, theHTE);
- TEDelete(theHTE);
-
- HLock((Handle)rawTextDesc.dataHandle);
-
- TEStylInsert((const void *) (*rawTextDesc.dataHandle),
- GetHandleSize(rawTextDesc.dataHandle),
- (StScrpHandle) textStyleDesc.dataHandle,
- theHTE);
-
- HUnlock((Handle)rawTextDesc.dataHandle);
-
- if (textStyleDesc.dataHandle)
- ignoreErr = AEDisposeDesc(&textStyleDesc);
-
- if (rawTextDesc.dataHandle)
- ignoreErr = AEDisposeDesc(&rawTextDesc);
-
- if (styledTextDesc.dataHandle)
- ignoreErr = AEDisposeDesc(&styledTextDesc);
-
- }
-
- }
- else
- DisplayErrorInScript(theHTE);
-
- if (myErr==noErr)
- ignoreErr = OSADispose(gScriptingComponent,
- myScriptID);
- }
-
- if (myCompiledText.dataHandle)
- ignoreErr = AEDisposeDesc(&myCompiledText);
-
- if (windowTextDesc.dataHandle)
- ignoreErr = AEDisposeDesc(&windowTextDesc);
-
- return(myErr);
-
- }
-
- /*
- Name : ExecuteDocument
- Purpose : Compiles the text of the supplied document and then executes it
- - does NOT keep a compiled version after execution
- */
- pascal OSErr ExecuteDocument(DPtr theDoc)
- {
- OSErr myErr;
- OSErr ignoreErr;
- TEHandle theHTE;
- AEDesc windowTextDesc;
- AEDesc myCompiledText;
- OSAID myScriptID;
- OSAID myExecutedScriptID;
-
- /*
- Initialise handles
- */
-
- myCompiledText.dataHandle = nil;
- windowTextDesc.dataHandle = nil;
-
- theHTE = theDoc->theText;
-
- HLock((Handle)(**theHTE).hText);
- myErr = AECreateDesc(typeChar,
- (Ptr)&(*(**theHTE).hText)[0],
- (**theHTE).teLength,
- &windowTextDesc);
-
- HUnlock((Handle)(**theHTE).hText);
-
- if (myErr==noErr)
- {
- myScriptID = 0; // Added for Gustav 1.0a8
-
- myErr = OSACompile(gScriptingComponent,
- &windowTextDesc,
- 0,
- &myScriptID);
-
- if (myErr==noErr)
- {
- myErr = OSAExecute(gScriptingComponent,
- myScriptID,
- kOSANullScript,
- 0,
- &myExecutedScriptID);
-
- if (myErr!=noErr)
- DisplayErrorInScript(theHTE);
-
- myErr = OSAGetSource(gScriptingComponent,
- myScriptID,
- typeStyledText,
- &myCompiledText);
- if (myErr==noErr)
- {
- /* Zap current contents and
- replace with returned source */
-
- TESetSelect(0, 32000, theHTE);
- TEDelete(theHTE);
-
- myErr = GetStyledTextFromDescIntoTEHandle(&myCompiledText, theHTE);
-
- if (myErr==noErr)
- ignoreErr = OSADispose(gScriptingComponent,
- myExecutedScriptID);
- }
-
- }
- else
- DisplayErrorInScript(theHTE);
-
- if (myErr==noErr)
- ignoreErr = OSADispose(gScriptingComponent,
- myScriptID);
- }
-
- if (myCompiledText.dataHandle)
- ignoreErr = AEDisposeDesc(&myCompiledText);
-
- if (windowTextDesc.dataHandle)
- ignoreErr = AEDisposeDesc(&windowTextDesc);
-
- return(myErr);
- }
-
- /*
- Name : ScriptForMenuExists
- Purpose: Tests for the existance of a valid script for a given menu item
- */
-
- pascal OSErr ScriptForMenuExists(short theMenu, short theItem, Boolean *exists)
- {
- short resID;
- OSAID myScriptID;
- OSErr myErr;
-
- myErr = noErr;
-
- resID = (theMenu<<5) + theItem;
-
- myScriptID = GetScriptIDForResID(resID);
-
- if (myScriptID==kOSANullScript)
- if (theItem!=0)
- myErr = ScriptForMenuExists(theMenu, 0, exists);
- else
- *exists = false;
- else
- *exists = true;
-
- return(myErr);
- } /* ScriptForMenuExists */
-
-
- /*
- Name : ExecuteScriptForMenu
- Purpose: Executes a script associated with the menu item.
- Should be called only after ScriptForMenuExists
- returns exists.
- */
- pascal OSErr ExecuteScriptForMenu(short theMenu, short theItem)
- {
- short resID;
- OSAID myScriptID;
- OSAID myExecuteID;
- OSErr myErr;
- OSErr ignoreErr;
-
- resID = (theMenu<<5) + theItem;
-
- myScriptID = GetScriptIDForResID(resID);
-
- if (myScriptID==kOSANullScript)
- {
- resID = (theMenu<<5); /* look for a script for the whole menu - item 0 */
- myScriptID = GetScriptIDForResID(resID);
- }
-
- if (myScriptID != kOSANullScript)
- {
- gActiveMenuItem = theItem;
-
- myErr = OSAExecute(gScriptingComponent,
- myScriptID,
- kOSANullScript,
- 0,
- &myExecuteID);
-
- ignoreErr = OSADispose(gScriptingComponent,
- myExecuteID);
-
- gActiveMenuItem = 0;
- }
-
- return(myErr);
- }
-
- /*
- Name : GetScriptActiveItem
- Purpose : Used by SVAppleEvents for the active item property of a menu.
- Allows a script associated with more than one menu item to
- find which menu item it was called by.
- */
- pascal short GetScriptActiveItem(void)
- {
- return(gActiveMenuItem);
- }
-
- /*
- Routines used in the StyledTextEdit Dialog Item
- */
-
- struct StyleTextInfo {
- ControlHandle theScrollBar;
- TEHandle theTEHandle;
- };
-
- typedef struct StyleTextInfo StyleTextInfo;
-
- typedef StyleTextInfo *pStyleTextInfo;
-
- pascal void DrawStyledTextEditRec(DialogPtr theDialog, short theItem)
- {
- short theType;
- Handle theHandle;
- Rect itemRect;
-
- GetDItem(theDialog, theItem, &theType, &theHandle, &itemRect);
- FrameRect(&itemRect);
- InsetRect(&itemRect, 5, 5);
-
- TEUpdate(&itemRect, ((pStyleTextInfo) GetWRefCon(theDialog))->theTEHandle);
- }
-
- pascal void DrawScrollBar(DialogPtr theDialog, short theItem)
- {
- #pragma unused (theItem)
-
- Draw1Control(((pStyleTextInfo) GetWRefCon(theDialog))->theScrollBar);
- }
-
- /*
- Name: SetDrawProcForUserItem
- Purpose: Installs a procedure that will be called when theItem needs
- to be drawn.
- */
- pascal void SetDrawProcForUserItem(DialogPtr theDialog, short theItem, ProcPtr theProc)
- {
- short theType;
- Handle theHandle;
- Rect itemRect;
-
- GetDItem(theDialog, theItem, &theType, &theHandle, &itemRect);
- SetDItem(theDialog, theItem, theType, (Handle)theProc, &itemRect);
- }
-
- /*
- Name: FlashButton
- Purpose: Provide visual effect of button having been
- selected.
- */
-
- pascal void FlashButton(DialogPtr theDialog, short theItem)
- {
- short theType;
- Handle theHandle;
- Rect itemRect;
-
- GetDItem(theDialog, theItem, &theType, &theHandle, &itemRect);
-
- HiliteControl((ControlHandle)theHandle, inButton);
- HiliteControl((ControlHandle)theHandle, 0);
- }
-
- /*
- Name: ScrollVActionProc
- Purpose: Called as scrollbar is tracked in buttons or page up/down.
- Keeps text in sync with scrollBar
- */
- pascal void ScrollVActionProc(ControlHandle control, short part)
- {
- short amount;
- short initialValue;
-
- if (part)
- {
- switch (part) {
- case inUpButton:
- case inDownButton : amount = 24;
- break;
- case inPageUp:
- case inPageDown : amount = (**control).contrlRect.bottom -
- (**control).contrlRect.top;
- break;
-
- } /* case */
-
- if (part == inUpButton || part == inPageUp)
- amount = -amount; /* reverse direction */
-
- initialValue = GetCtlValue(control);
-
- SetCtlValue(control, initialValue+amount); /* Pinned within Min/Max automatically */
-
- amount = GetCtlValue(control)-initialValue;
-
- if (amount)
- TEScroll(0, -amount, ((pStyleTextInfo)GetWRefCon((**control).contrlOwner))->theTEHandle);
-
- } /* if */
- } /* ScrollVActionProc */
-
- /*
- Name: TrackTEPosn
- Purpose: Ensures that the scrollbar value matches the position
- of the text edit record.
- */
- pascal void TrackTEPosn(ControlHandle theControl, TEHandle theHTE)
- {
- short shouldBe;
-
- shouldBe = (**theHTE).viewRect.top -
- (**theHTE).destRect.top;
-
- if (GetCtlValue(theControl)!=shouldBe)
- SetCtlValue(theControl,shouldBe);
- }
-
- /*
- Name: SetScrollLimit
- Purpose: Ensures that the maximum value of the scrollbar is sufficient
- to allow showing of all text, and no more.
- */
- pascal void SetScrollLimit(ControlHandle newScroll, TEHandle theHTE)
- {
- Point teLimit;
- short currentMax;
- short currentValue;
- TextStyle theStyle;
- short lineHeight;
- short fontAscent;
-
- currentMax = GetCtlMax(newScroll);
-
- /*
- Scroll max should be position of bottom of bottom line when unscrolled
- This is equal to
- The position of the bottom line relative to current position +
- The amount currently scrolled -
- The height of the visible part
- */
-
- teLimit = TEGetPoint((**theHTE).teLength, theHTE); // Position of bottom relative to current posn
-
- TEGetStyle((**theHTE).teLength, &theStyle, &lineHeight, &fontAscent,theHTE);
- teLimit.v += lineHeight-fontAscent; // Add in for descent - TEGetPoint is posn of baseline not bottom of chars
-
- teLimit.v += ((**theHTE).viewRect.top -(**theHTE).destRect.top); // Amount already scrolled
-
- teLimit.v -= ((**theHTE).viewRect.bottom - (**theHTE).viewRect.top); // Height of page
-
- if (teLimit.v<0) // Cannot be negative
- teLimit.v = 0;
-
- if (currentMax>teLimit.v)
- {
- currentValue = GetCtlValue(newScroll);
- if (currentValue>teLimit.v)
- {
- TEScroll(0, teLimit.v - currentValue, theHTE);
- SetCtlValue(newScroll, teLimit.v);
- }
- SetCtlMax(newScroll, teLimit.v);
- }
-
- if (currentMax<teLimit.v)
- SetCtlMax(newScroll, teLimit.v);
- }
-
- #define kCompile 3
- #define kTextItem 4
- #define kScrollBar 5
-
- pascal Boolean MyFilterProc(DialogPtr theDialog, EventRecord *myEvent, short *itemHit)
- {
- short myPart;
- WindowPtr whichWindow;
- TEHandle newTE;
- Boolean extend;
- GrafPtr oldPort;
- Point mousePt;
- char myKey;
- Boolean returnVal;
- long menuResult;
- Rect teItemRect;
- Rect scrollItemRect;
- ControlHandle newScroll;
- ControlHandle theControl;
- short part;
- short value;
- short cntlCode;
-
- GetPort(&oldPort);
-
- returnVal = false;
-
- newTE = ((pStyleTextInfo)GetWRefCon(theDialog))->theTEHandle;
- newScroll = ((pStyleTextInfo)GetWRefCon(theDialog))->theScrollBar;
-
- TEIdle(newTE);
-
- /* Maintain the cursor */
-
- SetPort(theDialog);
- GetMouse(&mousePt);
-
- GetRectOfDialogItem(theDialog, kTextItem, &teItemRect);
- GetRectOfDialogItem(theDialog, kScrollBar, &scrollItemRect);
-
- if (PtInRect(mousePt, &teItemRect))
- SetCursor(&editCursor);
- else
- SetCursor(&qd.arrow);
-
- switch (myEvent->what) {
- case mouseDown: myPart = FindWindow(myEvent->where, &whichWindow);
- if (whichWindow==theDialog)
- switch (myPart) {
- case inContent:
- case inGrow: SetPort(whichWindow);
- mousePt = myEvent->where;
- GlobalToLocal(&mousePt);
-
- extend = ((myEvent->modifiers & shiftKey) != 0);
- if (PtInRect(mousePt, &(*(newTE))->viewRect))
- {
- TEClick(mousePt, extend, newTE);
- TrackTEPosn(newScroll, newTE);
- }
-
- if (PtInRect(mousePt, &scrollItemRect))
- {
- cntlCode = FindControl(mousePt, theDialog, &theControl);
- if (theControl)
- if (cntlCode == inThumb)
- {
- value = GetCtlValue(theControl);
- part = TrackControl(theControl,
- mousePt,
- nil);
- if (part)
- {
- value -= GetCtlValue(theControl);
- if (value)
- TEScroll(0, value, newTE);
- } /* if */
- }
- else
- if (cntlCode!=0)
- part = TrackControl(theControl, mousePt, (ProcPtr)ScrollVActionProc);
- }
- break;
-
- case inDrag: DragWindow(whichWindow,
- myEvent->where,
- &qd.screenBits.bounds);
- returnVal = true; /* Stops modal dialog beeping */
- break;
-
- case inMenuBar: /* Allows turn on/off of ballon help */
- menuResult = MenuSelect(myEvent->where);
- break;
- }
- break;
- case keyDown:
- case autoKey: /* Need hooks here for command keys if menus enabled */
- myKey = myEvent->message & charCodeMask;
- if (myKey==3)
- {
- *itemHit = kCompile;
- FlashButton(theDialog, kCompile);
- returnVal = true;
- }
- else
- {
- TEKey(myKey, newTE);
- SetScrollLimit(newScroll, newTE);
- TrackTEPosn(newScroll, newTE);
- }
- break;
-
- case activateEvt: if (((myEvent->modifiers & activeFlag) != 0))
- if ((WindowPtr)myEvent->message == theDialog)
- TEActivate(newTE);
- else
- DoActivate((WindowPtr)myEvent->message, true); /* Should not get here! */
- else
- if ((WindowPtr)myEvent->message == theDialog)
- TEDeactivate(newTE);
- else
- DoActivate((WindowPtr)myEvent->message, false);
-
- break;
-
- case updateEvt : if (Ours((WindowPtr)myEvent->message))
- DoUpdate(DPtrFromWindowPtr((WindowPtr)myEvent->message));
- break;
- }
-
- SetPort(oldPort);
-
- return(returnVal);
- }
-
- pascal OSErr EditMenuScript(short theMenu, short theItem)
- {
- short resID;
- OSAID myScriptID;
- OSErr myErr;
- OSErr ignoreErr;
- AEDesc scriptTextDesc;
- DialogPtr scriptEditDlog;
- short itemHit;
- TEHandle newTE;
- GrafPtr oldPort;
- Rect itemRect;
- OSAID myCompiledID;
- Handle myScript;
- Boolean wholeMenu;
- ControlHandle myScrollBar;
- StyleTextInfo theStyleTextInfo;
-
- GetPort(&oldPort);
-
- /*
- Look for a script associated with theItem first,
- and if not found look for one associated with
- the whole menu
- */
-
- wholeMenu = false;
-
- resID = (theMenu<<5) + theItem;
-
- myScriptID = GetScriptIDForResID(resID);
-
- if (myScriptID==kOSANullScript)
- {
- resID = (theMenu<<5);
- myScriptID = GetScriptIDForResID(resID);
- wholeMenu = true;
- }
-
- scriptEditDlog = GetNewDialog(400, nil, (WindowPtr)-1);
- SetPort(scriptEditDlog);
- /*
- Create a styled text edit record for the userItem
- and install it
- */
- GetRectOfDialogItem(scriptEditDlog, kTextItem, &itemRect);
-
- InsetRect(&itemRect, 5, 5);
-
- newTE = TEStylNew(&itemRect, &itemRect);
-
- TEAutoView(true, newTE);
-
- SetDrawProcForUserItem(scriptEditDlog, kTextItem,(ProcPtr)DrawStyledTextEditRec);
-
- /*
- Now create a scrollbar and install it
- */
-
- GetRectOfDialogItem(scriptEditDlog, kScrollBar, &itemRect);
-
- myScrollBar = NewControl(scriptEditDlog,
- &itemRect,
- "",
- true,
- 0,
- 0,
- 32000, // Will be fixed up later - by SetScrollLimit()
- scrollBarProc,
- 0);
-
- SetDrawProcForUserItem(scriptEditDlog, kScrollBar,(ProcPtr)DrawScrollBar);
-
- /*
- Use the dialog window refcon to allow access to the
- TEHandle and scrollHandle avoiding the use
- of globals
- */
-
- theStyleTextInfo.theTEHandle = newTE;
- theStyleTextInfo.theScrollBar = myScrollBar;
-
- SetWRefCon(scriptEditDlog, (long) &theStyleTextInfo);
-
- /*
- Put the source of the script into the
- text edit record
- */
-
- myErr = OSAGetSource(gScriptingComponent,
- myScriptID,
- typeStyledText,
- &scriptTextDesc);
- GetStyledTextFromDescIntoTEHandle(&scriptTextDesc, newTE);
-
- ignoreErr = AEDisposeDesc(&scriptTextDesc);
-
- SetScrollLimit(myScrollBar, newTE);
- TrackTEPosn(myScrollBar, newTE);
-
- do {
- ModalDialog((ModalFilterProcPtr)MyFilterProc, &itemHit);
- switch (itemHit){
- case ok :
- case kCompile : SetCursor(&waitCursor);
- HLock((Handle)(**newTE).hText);
- myErr = AECreateDesc(typeChar,
- (Ptr)*((**newTE).hText),
- (**newTE).teLength,
- &scriptTextDesc);
-
- HUnlock((Handle)(**newTE).hText);
-
- myCompiledID = 0; // Added for Gustav 1.0a8
- myErr = OSACompile(gScriptingComponent,
- &scriptTextDesc,
- 0,
- &myCompiledID);
-
- ignoreErr = AEDisposeDesc(&scriptTextDesc);
-
- scriptTextDesc.dataHandle = nil;
-
- if (myErr==noErr)
- {
- myErr = OSAGetSource(gScriptingComponent,
- myCompiledID,
- typeStyledText,
- &scriptTextDesc);
-
- /* Zap current contents and
- replace with returned source */
-
- TESetSelect(0, 32000, newTE);
- TEDelete(newTE);
- SetCtlValue(myScrollBar, 0); // We deleted all the text so it won't be scrolled anymore
-
- GetStyledTextFromDescIntoTEHandle(&scriptTextDesc, newTE);
-
- DrawStyledTextEditRec(scriptEditDlog, kTextItem);
-
- ignoreErr = AEDisposeDesc(&scriptTextDesc);
- }
- else
- {
- DisplayErrorInScript(newTE);
- itemHit = 0; // Stop dialog going away
- }
-
- SetScrollLimit(myScrollBar, newTE);
- TrackTEPosn(myScrollBar, newTE);
-
- SetCursor(&qd.arrow);
-
- if (itemHit==ok)
- if (myErr==noErr)
- {
- // Swap this script for the old one unless whole menu
-
- if (wholeMenu)
- myScriptID = kOSANullScript;
-
- myErr = OSACopyID(gScriptingComponent,
- myCompiledID,
- &myScriptID);
-
- myErr = OSAStore(gScriptingComponent,
- myScriptID,
- typeOSAGenericStorage,
- 0,
- &scriptTextDesc);
-
- if (myErr==noErr)
- {
- /* should prompt for whole menu if mod 32 == 0 */
-
- resID = (theMenu<<5) + theItem;
-
- /* Remove it if it's already in the prefs file */
-
- myScript = Get1Resource(kCompiledScriptType, resID);
-
- if (myScript!=nil && ResError()==noErr)
- RmveResource(myScript);
-
- /* And create a new resource */
-
- myScript = scriptTextDesc.dataHandle;
-
- HLock((Handle)myScript);
- HandToHand(&myScript);
- AddResource(myScript, kCompiledScriptType, resID, "\pMenu Script");
- UpdateResFile(CurResFile());
- HUnlock((Handle)myScript);
-
- if (wholeMenu)
- AddMenuScript(resID, myScriptID);
- }
- myErr = AEDisposeDesc(&scriptTextDesc);
- }
- else
- itemHit = -1;
-
- ignoreErr = OSADispose(gScriptingComponent,
- myCompiledID);
-
- case cancel :
- case kTextItem :
- case kScrollBar: break;
- }
- } while (itemHit!=ok && itemHit!=cancel);
-
- DisposeDialog(scriptEditDlog);
-
- SetPort(oldPort);
-
- return(noErr);
- }